#include "sbrush_dag.h"

using namespace sbrush;
using namespace dag;

namespace {
	bool are_compatible(const SMS_Data& data, const Frame& frame) {
		FrameSpec newSpec;
		sms_2_spec(data, newSpec);
		return (static_cast<const FrameSpec&>(frame) == newSpec);
	}
}


IncompatibleConversion::IncompatibleConversion() 
:	AcsError("incompatible conversion")
{
}

IncompatibleConversion::~IncompatibleConversion() throw() {
}

void sbrush::sms_2_spec(const SMS_Data& data, FrameSpec& spec) {
	spec.bSize = 0;
	spec.iSize = 0;
	spec.dSize = 0;
	spec.fSize = 2 * data.nTracks + data.nCoeff + data.nEnvCoeff + 1;
}

void sbrush::sms_2_frame(Frame& frame, const SMS_Data& data) {
	if (!are_compatible(data, frame)) {
		throw IncompatibleConversion();
	}
	
	size_t pos = 0;
	/* deterministic tracks */
	if (data.nTracks > 0) {
		memcpy(&frame.floats[pos], data.pFSinFreq, data.nTracks * sizeof(float));
		pos += data.nTracks;
		memcpy(&frame.floats[pos], data.pFSinAmp, data.nTracks * sizeof(float));
		pos += data.nTracks;
	}
	/* stochastic gain is just a single value */
	frame.floats[pos] = *data.pFStocGain;
	pos++;
	/* noise coefficients */
	if (data.nCoeff > 0) {
		memcpy(&frame.floats[pos], data.pFStocCoeff, data.nCoeff * sizeof(float));
		pos += data.nCoeff;
	}
	/* noise envelope */
	if (data.nEnvCoeff > 0) {
		memcpy(&frame.floats[pos], data.pSpecEnv, data.nEnvCoeff * sizeof(float));
	}
}

void sbrush::frame_2_sms(SMS_Data& data, const Frame& frame) {
	if (!are_compatible(data, frame)) {
		throw IncompatibleConversion();
	}
		
	size_t pos = 0;
	/* deterministic tracks */
	if (data.nTracks > 0) {
		memcpy(data.pFSinFreq, &frame.floats[pos], data.nTracks * sizeof(float));
		pos += data.nTracks;
		memcpy(data.pFSinAmp, &frame.floats[pos], data.nTracks * sizeof(float));
		pos += data.nTracks;
	}
	/* stochastic gain is just a single value */
	*data.pFStocGain = frame.floats[pos];
	pos++;
	/* noise coefficients */
	if (data.nCoeff > 0) {
		memcpy(data.pFStocCoeff, &frame.floats[pos], data.nCoeff * sizeof(float));
		pos += data.nCoeff;
	}
	/* noise envelope */
	if (data.nEnvCoeff > 0) {
		memcpy(data.pSpecEnv, &frame.floats[pos], data.nEnvCoeff * sizeof(float));
	}
}
